package com.ruoyi.project.hbase;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.alibaba.fastjson.JSONObject;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.flink.util.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hbase.thirdparty.com.google.common.base.CaseFormat;

/**
 * Hbase 操作工具类
 *
 */
@Slf4j
public class HbaseUtils {

    /*Configuration config = HBaseConfiguration.create();
    Connection connection;
    Admin admin;

    //初始化提供  hbase ip 和 zk端口
    public HbaseUtils(String ip, String port, String master) throws IOException {
        this.config.set("hbase.zookeeper.quorum", ip);
        this.config.set("hbase.zookeeper.property.clientPort", port);
        this.config.set("hbase.master", master);
        this.connection = ConnectionFactory.createConnection(this.config);
        admin=connection.getAdmin();
    }

    // ===============Common=====================================

    *//**
     * 根据表名获取Table对象
     *
     * @param name 表名，必要时可指定命名空间，比如：“default:user”
     * @return Hbase Table 对象
     * @throws IOException 有异常抛出，由调用者捕获处理
     *//*
    public static Table getTable(String name) throws IOException {
        TableName tableName = TableName.valueOf(name);
        Connection connection = ConnectionFactory.createConnection();
        return connection.getTable(tableName);
    }

    // =============== Put =====================================

    *//**
     * 根据rowKey生成一个Put对象
     *
     * @param rowKey rowKey
     * @return Put对象
     *//*
    public static Put createPut(String rowKey) {
        return new Put(Bytes.toBytes(rowKey));
    }

    *//**
     * 在Put对象上增加Cell
     *
     * @param put Put对象
     * @param cell cell对象
     * @throws IOException 有异常抛出，由调用者捕获处理
     *//*
    public static void addCellOnPut(Put put, Cell cell) throws IOException {
        put.add(cell);
    }

    *//**
     * 在Put对象上增加值
     *
     * @param put Put对象
     * @param family 列簇
     * @param qualifier 列
     * @param value 字符串类型的值
     *//*
    public static void addValueOnPut(Put put, String family, String qualifier, String value) {
        addValueOnPut(put, family, qualifier, Bytes.toBytes(value));
    }

    *//**
     * 在Put对象上增加值
     *
     * @param put Put对象
     * @param family 列簇
     * @param qualifier 列
     * @param value 字节数组类型的值，可以是任意对象序列化而成
     *//*
    public static void addValueOnPut(Put put, String family, String qualifier, byte[] value) {
        put.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier), value);
    }

    *//**
     * 在Put对象上增加值
     *
     * @param put Put对象
     * @param family 列簇
     * @param qualifier 列
     * @param ts Timestamp时间戳
     * @param value 字符串类型的值
     *//*
    public static void addValueOnPut(Put put, String family, String qualifier, long ts, String value) {
        addValueOnPut(put, family, qualifier, ts, Bytes.toBytes(value));
    }

    *//**
     * 在Put对象上增加值
     *
     * @param put Put对象
     * @param family 列簇
     * @param qualifier 列
     * @param ts Timestamp时间戳
     * @param value 字节数组类型的值，可以是任意对象序列化而成
     *//*
    public static void addValueOnPut(Put put, String family, String qualifier, long ts, byte[] value) {
        put.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier), ts, value);
    }

    *//**
     * 按表名插入一个Put对象包含的数据
     *
     * @param tableName 表名，必要时可指定命名空间，比如：“default:user”
     * @param put 要插入的数据对象
     * @throws IOException 有异常抛出，由调用者捕获处理
     *//*
    public static void put(String tableName, Put put) throws IOException {
        try (
                Table table = getTable(tableName);
        ) {

            table.put(put);
        }
    }

    *//**
     * 按表名批量插入Put对象包含的数据
     *
     * @param tableName 表名，必要时可指定命名空间，比如：“default:user”
     * @param puts 要插入的数据对象集合
     * @throws IOException 有异常抛出，由调用者捕获处理
     *//*
    public static void put(String tableName, List<Put> puts) throws IOException {
        try (
                Table table = getTable(tableName);
        ) {

            table.put(puts);
        }
    }

    // =============== Get =====================================

    *//**
     * 根据rowKey生成一个查询的Get对象
     *
     * @param rowKey rowKey
     * @return Get 对象
     *//*
    public static Get createGet(String rowKey) {
        return new Get(Bytes.toBytes(rowKey));
    }

    *//**
     * 对查询的Get对象增加指定列簇
     *
     * @param get
     * @param family
     *//*
    public static void addFamilyOnGet(Get get, String family) {
        get.addFamily(Bytes.toBytes(family));
    }

    *//**
     * 对查询的Get对象增加指定列簇和列
     *
     * @param get
     * @param family
     * @param qualifier
     *//*
    public static void addColumnOnGet(Get get, String family, String qualifier) {
        get.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));
    }

    *//**
     * 根据表名和rowKey查询结果（包含全部列簇和列）
     *
     * @param tableName 表名，必要时可指定命名空间，比如：“default:user”
     * @param rowKey 查询rowKey
     * @return 查询结果Result
     * @throws IOException 有异常抛出，由调用者捕获处理
     *//*
    public static Result get(String tableName, String rowKey) throws IOException {
        Get get = createGet(rowKey);
        return get(tableName, get);
    }

    *//**
     * 根据表名和rowKey数组批量查询结果（包含全部列簇和列）
     *
     * @param tableName 表名，必要时可指定命名空间，比如：“default:user”
     * @param rowKeys 查询rowKey数组
     * @return 查询结果Result数组
     * @throws IOException 有异常抛出，由调用者捕获处理
     *//*
    public static Result[] get(String tableName, String[] rowKeys) throws IOException {
        List<Get> gets = new ArrayList<Get>();
        for (String rowKey : rowKeys) {
            gets.add(createGet(rowKey));
        }
        return get(tableName, gets);
    }

    *//**
     * 根据表名和Get对象查询结果
     *
     * @param tableName 表名，必要时可指定命名空间，比如：“default:user”
     * @param get Hbase查询对象
     * @return 查询结果Result
     * @throws IOException 有异常抛出，由调用者捕获处理
     *//*
    public static Result get(String tableName, Get get) throws IOException {
        try (
                Table table = getTable(tableName);
        ) {

            return table.get(get);
        }
    }

    *//**
     * 根据表名和Get对象数组查询结果
     *
     * @param tableName 表名，必要时可指定命名空间，比如：“default:user”
     * @param gets 多个Hbase查询对象组成的数组
     * @return 查询结果Result数组
     * @throws IOException 有异常抛出，由调用者捕获处理
     *//*
    public static Result[] get(String tableName, List<Get> gets) throws IOException {
        try (
                Table table = getTable(tableName);
        ) {
            return table.get(gets);
        }
    }

    // =============== Scan =====================================

    *//**
     * 根据startRow和stopRow创建扫描对象
     *
     * @param startRow 扫描开始行，结果包含该行
     * @param stopRow 扫描结束行，结果不包含该行
     * @return Scan对象
     *//*
    public static Scan createScan(String startRow, String stopRow) {
        Scan scan = new Scan();
        scan.withStartRow(Bytes.toBytes(startRow));
        scan.withStopRow(Bytes.toBytes(stopRow));
        return scan;
    }

    *//**
     * 对扫描对象设置列簇
     *
     * @param scan 扫描对象
     * @param family 列簇
     *//*
    public static void addFamilyOnScan(Scan scan, String family) {
        scan.addFamily(Bytes.toBytes(family));
    }

    *//**
     * 对扫描对象设置列
     *
     * @param scan 扫描对象
     * @param family 列簇
     * @param qualifier 列簇下对应的列
     *//*
    public static void addColumnOnScan(Scan scan, String family, String qualifier) {
        scan.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));
    }

    *//**
     * 根据表名和扫描对象扫描数据
     *
     * @param tableName 表名，必要时可指定命名空间，比如：“default:user”
     * @param scan 扫描对象
     * @return 扫描结果集对象ResultScanner
     * @throws IOException 有异常抛出，由调用者捕获处理
     *//*
    public static ResultScanner scan(String tableName, Scan scan) throws IOException {
        try (
                Table table = getTable(tableName);
        ) {
            return table.getScanner(scan);
        }
    }

    *//**
     * 根据表名、开始行和结束行扫描数据（结果包含开始行，不包含结束行，半开半闭区间[startRow, stopRow)）
     *
     * @param tableName 表名，必要时可指定命名空间，比如：“default:user”
     * @param startRow 扫描开始行
     * @param stopRow 扫描结束行
     * @return 扫描结果集对象ResultScanner
     * @throws IOException 有异常抛出，由调用者捕获处理
     *//*
    public static ResultScanner scan(String tableName, String startRow, String stopRow) throws IOException {
        return scan(tableName, createScan(startRow, stopRow));
    }

    // =============== Delete =====================================

    *//**
     * 根据rowKey生成一个查询的Delete对象
     *
     * @param rowKey rowKey
     * @return Delete对象
     *//*
    public static Delete createDelete(String rowKey) {
        return new Delete(Bytes.toBytes(rowKey));
    }

    *//**
     * 在Delete对象上增加Cell
     *
     * @param delete Delete对象
     * @param cell cell对象
     * @throws IOException 有异常抛出，由调用者捕获处理
     *//*
    public static void addCellOnDelete(Delete delete, Cell cell) throws IOException {
        delete.add(cell);
    }

    *//**
     * 对删除对象增加指定列簇
     *
     * @param delete Delete对象
     * @param family 列簇
     *//*
    public static void addFamilyOnDelete(Delete delete, String family) {
        delete.addFamily(Bytes.toBytes(family));
    }

    *//**
     * 对删除对象增加指定列簇和列
     *
     * @param delete Delete对象
     * @param family 列簇
     * @param qualifier 列
     *//*
    public static void addColumnOnDelete(Delete delete, String family, String qualifier) {
        delete.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));
    }

    *//**
     * 按表名删除一个Delete对象指定的数据
     *
     * @param tableName 表名，必要时可指定命名空间，比如：“default:user”
     * @param delete Delete对象
     * @throws IOException 有异常抛出，由调用者捕获处理
     *//*
    public static void delete(String tableName, Delete delete) throws IOException {
        try (
                Table table = getTable(tableName);
        ) {
            table.delete(delete);
        }
    }

    *//**
     * 按表名批量删除Delete对象集合包含的指定数据
     *
     * @param tableName 表名，必要时可指定命名空间，比如：“default:user”
     * @param deletes Delete对象集合
     * @throws IOException 有异常抛出，由调用者捕获处理
     *//*
    public static void delete(String tableName, List<Delete> deletes) throws IOException {
        try (
                Table table = getTable(tableName);
        ) {
            table.delete(deletes);
        }
    }*/

    public static Connection getHBaseConnection() {

        try {
            // 1.获取配置文件信息
            Configuration configuration = HBaseConfiguration.create();
            configuration.set("hbase.zookeeper.quorum", "192.168.33.207");
//            configuration.set("hbase.zookeeper.property.clientPort", "2181");//可写可不写,默认为2181

            // 2.创建连接对象
            return ConnectionFactory.createConnection(configuration);

        } catch (IOException e) {
            log.error("获取Hbase相关基础信息失");
            e.printStackTrace();
        }
        return null;
    }

//    static {
//        try {
//            // 1.获取配置文件信息
//            Configuration configuration = HBaseConfiguration.create();
//            configuration.set("hbase.zookeeper.quorum", "localhost");
//            configuration.set("hbase.zookeeper.property.clientPort", "2181");//可写可不写,默认为2181
//
//            // 2.创建连接对象
//            connection = ConnectionFactory.createConnection(configuration);
//
//            // 3.创建Admin对象
//            admin = connection.getAdmin();
//
//        } catch (IOException e) {
//            log.error("获取Hbase相关基础信息失");
//            e.printStackTrace();
//        }
//    }

    /**
     * @param tableName
     * @return true or false
     * @throws IOException
     * @author aaronChen
     * @description 判断表是否存在
     */
    public static boolean isTableExist(String tableName, Admin admin) throws IOException {
        // 1.判断表是否存在
        boolean exists = admin.tableExists(TableName.valueOf(tableName));

        // 2.返回结果
        return exists;
    }


    /**
     * @param tableName               需要创建的hbase表名,格式必须要是 命名空间:tablename
     * @param cfs                     可以同时传入多个列簇
     * @param createNameSpaceIfExists 如果命名空间不存在，是否创建
     * @throws IOException
     * @author aaronChen
     * @description 创建表
     */
    public static boolean createTable(Admin admin, String tableName, boolean createNameSpaceIfExists, String... cfs) throws IOException {

        //1、判断传入的表是否正确
        if (tableName.split(":").length != 2) {
            log.error("{},传入的表名有问题，需要传入 nameSpace:tableName 这种格式", tableName);
            return false;
        }

        String nameSpace = tableName.split(":")[0];

        //2、判断命名空间相关信息
        if (!isNameSpaceExist(admin, nameSpace)) {
            if (createNameSpaceIfExists) {
                log.info("{},该命名空间不存在，开始创建该命名空间", nameSpace);
                createNameSpace(admin, nameSpace);
            } else {
                log.error("{},该命名空间不存在", nameSpace);
                return false;
            }
        }

        // 3、判断表是否存在
        if (isTableExist(tableName, admin)) {
            log.error("{},表已存在", tableName);
            return false;
        }

        // 4、判断是否存在列族信息
        if (cfs.length <= 0) {
            log.info("请设置列族信息!");
            return false;
        }

        // 5、创建表描述器
        try {
            if (admin.tableExists(TableName.valueOf(tableName))) {
                return false;
            }
            //定义表描述对象
            TableDescriptorBuilder tableDescriptorBuilder = TableDescriptorBuilder.newBuilder(TableName.valueOf(tableName));
            //遍历列族数组
            for (String cf : cfs) {
                //定义列族描述对象
                ColumnFamilyDescriptor columnFamily = ColumnFamilyDescriptorBuilder.of(cf);
                //给表添加列族信息
                tableDescriptorBuilder.setColumnFamily(columnFamily);
            }
            //创建表
            admin.createTable(tableDescriptorBuilder.build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

        log.info("{},表新建成功", tableName);

        return true;

    }

    /**
     * @param tableName
     * @throws IOException
     * @author aaronChen
     * @description 删除表
     */
    public static void dropTable(Admin admin, String tableName) throws IOException {

        // 1.判断表是否存在
        if (!isTableExist(tableName, admin)) {
            log.error("{},表不存在", tableName);
            return;
        }

        // 2.使表下线
        admin.disableTable(TableName.valueOf(tableName));

        // 3.删除表
        admin.deleteTable(TableName.valueOf(tableName));
    }

    /**
     * @param nameSpace
     * @return true or false
     * @throws IOException
     * @author aaronChen
     * @description 判断一个命名空间是否存在
     */
    public static boolean isNameSpaceExist(Admin admin, String nameSpace) throws IOException {
        NamespaceDescriptor[] namespaceDescriptors = admin.listNamespaceDescriptors();
        for (NamespaceDescriptor namespaceDescriptor : namespaceDescriptors) {
            if (namespaceDescriptor.getName().equals(nameSpace)) {
                return true;
            }
        }
        return false;
    }

    /**
     * @param namespace
     * @author aaronChen
     * @description 创建命名空间
     */
    public static void createNameSpace(Admin admin, String namespace) {

        // 1.创建命名空间描述器
        NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create(namespace).build();

        // 2.创建命名空间
        try {
            admin.createNamespace(namespaceDescriptor);
        } catch (NamespaceExistException e) {
            log.error("{},命名空间已存在", namespace);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * @param tableName
     * @param rowKey
     * @param columnFamily
     * @param columnName
     * @param value
     * @throws IOException
     * @author aaronChen
     * @description 向表中插入数据
     */
    public static void putData(Connection connection, String tableName, String rowKey, String columnFamily, String columnName, String value) throws IOException {
        // 1.获取表对象
        Table table = connection.getTable(TableName.valueOf(tableName));

        // 2.创建put对象
        Put put = new Put(Bytes.toBytes(rowKey));

        // 3.给Put对象赋值
        put.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes(columnName), Bytes.toBytes(value));

        // 4.插入数据
        table.put(put);

        // 5.关闭表连接
        table.close();
    }


    /**
     * @param tableName
     * @param clz
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> T getData(Connection connection, String tableName, String rowKey, String columnFamily, String columnName, boolean underScoreToCamel, Class<T> clz) throws Exception {

        //1、判断传入的参数是否为空或空字符串
        if (StringUtils.isNullOrWhitespaceOnly(tableName)) {
            log.error("传入的tableName为空:{}", tableName);
            return null;
        }

        if (StringUtils.isNullOrWhitespaceOnly(rowKey)) {
            log.error("传入的rowKey为空:{}", rowKey);
            return null;
        }

        if (StringUtils.isNullOrWhitespaceOnly(columnFamily)) {
            log.error("传入的columnFamily为空:{}", columnFamily);
            return null;
        }

        Get get = new Get(Bytes.toBytes(rowKey));

        if (StringUtils.isNullOrWhitespaceOnly(columnName)) {
            get.addFamily(Bytes.toBytes(columnFamily));
//            log.info("传入的columnName为空:{},将根据传入的其他信息查询全量的列信息", columnName);
        } else {
            //传入的不为空的话，就查询传入的值
            get.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes(columnName));
//            log.info("传入的columnName为:{},将根据传入的值查询信息", columnName);
        }

        //4、获取表对象
        Table table = connection.getTable(TableName.valueOf(tableName));

        //5、设置获取数据的版本数
        //get.setMaxVersions(5);

        //5、获取数据
        Result resultData = table.get(get);

        //6、关闭表连接
        table.close();

        //创建 泛型对象
        T t = clz.newInstance();

        //给泛型对象赋值

        List<Cell> cells = resultData.listCells();

        for (Cell cell : cells) {

            String resultColumnName = Bytes.toString(CellUtil.cloneQualifier(cell));
            String resultValue = Bytes.toString(CellUtil.cloneValue(cell));

            //判断是否需要转换为驼峰命名
            if (underScoreToCamel) {

                if (resultColumnName.contains("_")) {
                    resultColumnName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, resultColumnName.toLowerCase());
                } else if (resultColumnName.contains("-")) {
                    resultColumnName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, resultColumnName.toLowerCase());
                } else {
                    resultColumnName = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_CAMEL, resultColumnName);
                }

            }

            BeanUtils.setProperty(t, resultColumnName, resultValue);
        }

        return t;

    }


    /**
     * @param tableName
     * @return 返回一个 JSONArray
     * <p>
     * [
     * {
     * "rowKey":"11111",
     * "value":[
     * {
     * "columnFamily":"first",
     * "columnValue":{
     * "name":"aaron",
     * "age":18
     * }
     * },
     * {
     * "columnFamily":"second",
     * "columnValue":{
     * "name":"aaron",
     * "age":18
     * }
     * }
     * ]
     * },
     * {
     * "rowKey":"22222",
     * "value":[
     * {
     * "columnFamily":"first",
     * "columnValue":{
     * "name":"wwww",
     * "age":19
     * }
     * },
     * {
     * "columnFamily":"second",
     * "columnValue":{
     * "name":"cccc",
     * "age":18,
     * "address","NanJ"
     * }
     * }
     * ]
     * }
     * ]
     * @throws IOException
     * @author aaronChen
     * @description 扫描全表数据
     * @deprecated
     */
    private static void scanTable(Connection connection, String tableName, String leftScanRowKey, String rightScanRowKey) throws IOException {


        // 1.获取表对象
        Table table = connection.getTable(TableName.valueOf(tableName));

        // 2.构建Scan对象 // 左闭右开
        Scan scan = new Scan(Bytes.toBytes(leftScanRowKey), Bytes.toBytes(rightScanRowKey));

        // 3.扫描表
        ResultScanner resultScanner = table.getScanner(scan);

        // 4.解析resultScanner
        for (Result result : resultScanner) {

            // 5.解析result并打印
            for (Cell cell : result.rawCells()) {

                // 6.打印数据
                System.out.println("RowKey:" + Bytes.toString(CellUtil.cloneRow(cell)) +
                        "，CF:" + Bytes.toString(CellUtil.cloneFamily(cell)) +
                        "，CN:" + Bytes.toString(CellUtil.cloneQualifier(cell)) +
                        "，Value:" + Bytes.toString(CellUtil.cloneValue(cell)));
            }
        }

        // 7.关闭表连接
        table.close();
    }


    /**
     * @param tableName 要删除的表名
     * @param rowKey    要删除的rowKey
     * @param cf        要删除的列簇
     * @param cn        要删除的列名
     * @throws IOException
     * @description Delete标记: 删除特定列列指定的版本
     * DeleteFamily标记: 删除特定列族所有列
     * DeleteColumn标记: 删除特定列的所有版本
     * 指定rowkey: 使用DeleteFamily标记
     * ---->不加时间戳表示删除[指定rowkey]的所有数据,加时间戳表示删除[指定rowkey]中[时间戳版本小于或等于指定时间戳]的所有数据
     * 指定rowkey+columnFamily: 使用DeleteFamily标记
     * ---->不加时间戳表示删除[指定列族]的所有数据,加了时间戳就表示删除[指定列族]下[时间戳版本小于或等于指定时间戳]的所有数据
     * 指定rowkey+columnFamily+column(addColumns): 使用DeleteColumn标记
     * ---->不加时间戳表示删除[指定列]所有版本的数据,加时间戳表示删除[指定列]中[时间戳版本小于或等于指定时间戳]的所有数据。
     * 指定rowkey+columnFamily+column(addColumn): 使用Delete标记 (只删除单个版本数据,生产环境尽量别用)
     * ---->不加时间戳表示删除[指定列]中[最新版本]的数据,加时间戳表示删除[指定列]中[指定时间戳版本]的数据。
     * ---->不推荐的原因是:操作不同(如flush前后操作产生的结果会不一样)结果可能不同
     * 如:在flush前如果有多个版本的数据,此时进行addColumn(不加时间戳)操作,会将最新版本的数据删除,然后老版本的数据会出现
     * 在flush后进行addColumn(不加时间戳)操作,会将最新版本的数据删除,而此时flush已将老版本的数据进行了删除,所有此时老版本的数据就不会出现了
     * <p>
     * 删除列最好使用addColumns
     * addColumns:不加时间戳表示删除指定列所有版本的数据(推荐)
     * addColumns:加时间戳表示删除时间戳小于或等于指定时间戳的指定列的所有版本。
     * addColumn:不加时间戳表示删除最新版本的数据,操作不同(如flush前后操作产生的结果会不一样)结果可能不同
     * addColumn:加时间戳表示删除指定时间戳的指定列版本的数据。
     */
    public static void deleteData(Connection connection, String tableName, String rowKey, String cf, String cn) throws IOException {

        // 1.获取表对象
        Table table = connection.getTable(TableName.valueOf(tableName));

        // 2.创建删除对象
        Delete delete = new Delete(Bytes.toBytes(rowKey));


        //delete.addColumns(Bytes.toBytes(cf), Bytes.toBytes(cn));
        //delete.addColumns(Bytes.toBytes(cf), Bytes.toBytes(cn),1574158036021L);

        //delete.addColumn(Bytes.toBytes(cf), Bytes.toBytes(cn));
        //delete.addColumn(Bytes.toBytes(cf), Bytes.toBytes(cn),1574158036021L);

        // 2.2 删除指定的列族
        // addFamily:删除指定列族的所有列的所有版本数据。
        delete.addFamily(Bytes.toBytes(cf));

        // 3.执行删除操作
        table.delete(delete);

        // 4.关闭连接
        table.close();
    }

    /**
     * @author aaronChen
     * @description 关闭资源
     */
    public static void close(Admin admin, Connection connection) {

        if (admin != null) {
            try {
                admin.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }



    public static JSONObject getJSONObject(String rowKey, List<Cell> cells) {

        /**
         * @return JSONObject {
         *       "rowKey":"11111",
         *      "value":{
         *      "name":"aaron",
         *      "age":18
         *            }
         *      }
         */
        JSONObject jsonObject = new JSONObject();
        JSONObject valueJsonObject = new JSONObject();

        for (Cell cell : cells) {
            valueJsonObject.put(Bytes.toString(CellUtil.cloneQualifier(cell)), Bytes.toString(CellUtil.cloneValue(cell)));
        }

        jsonObject.put("rowKey", rowKey);
        jsonObject.put("value", valueJsonObject);
        return jsonObject;
    }

    @SneakyThrows
    public static void main(String[] args) {
        createTable(getHBaseConnection().getAdmin(),"aaron1:test1",true,"name","age","id");
    }
}
